Terraform で Auto Mode の EKS クラスターを作成して、Pod Identity で AWS 権限を与えたアプリケーションをデプロイしてみた

Terraform で Auto Mode の EKS クラスターを作成して、Pod Identity で AWS 権限を与えたアプリケーションをデプロイしてみた

今回は Auto Mode の EKS クラスターを Terraform で作ってみようと思います。
また、Auto Mode には Pod Identity エージェントの設定不要で Pod Identity を利用できるメリットがあるので、合わせて試してみます。

Auto Mode とは?

ノードやアドオンの管理を AWS 側にオフロードできる EKS の新しい機能です。

https://aws.amazon.com/jp/blogs/news/streamline-kubernetes-cluster-management-with-new-amazon-eks-auto-mode/

https://dev.classmethod.jp/articles/eks-auto-mode/

Pod Identity とは?

昨年末のアップデートで利用できるようになった、ServiceAccount 単位で Pod へ AWS 権限を付与できる機能です。

https://dev.classmethod.jp/articles/eks-pod-identity-terraform-blue-green-upgrade/

旧来から存在する IRSA(IAM Roles for Service Accounts)でも Service Account 単位での権限管理を行うことは可能ですが、IAM ロールの信頼ポリシーとマニフェストファイルでの annotations 設定を両方行う必要があります。

信頼ポリシーに下記のような Open ID Connect プロバイダーから AssumeRole する許可設定を行う必要があります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "arn:aws:iam::111122223333:oidc-provider/oidc.eks.region-code.amazonaws.com/id/EXAMPLED539D4633E53DE1B71EXAMPLE"
      },
      "Action": "sts:AssumeRoleWithWebIdentity"
    }
  ]
}

また、Kubernetes のマニフェストファイル側でも annotations 設定を行う必要があります。

apiVersion: v1
kind: ServiceAccount
metadata:
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::444455556666:role/account-b-role

IRSA で別のアカウントに対して認証する

Pod Identity を利用することで、AWS 側の設定だけでより簡潔に設定を行うことができます。
ただ、Pod Identity Agent という専用エージェントをインストールする必要があり、利用する前に一手間必要でした。
Auto Mode の場合はこの辺りもプリインストールされているので、より簡単に利用することができます。

やってみる

Terraform で EKS を作成して、FastAPI のアプリケーションをデプロイします。
アプリケーションから DynamoDB にアクセスして、AWS の権限を扱えることを確認します。
本ブログでは特徴的な部分についてのみ説明しますが、利用したファイルは下記リポジトリにアップロードしました。
もし興味があればご参照下さい。

https://github.com/masutaro99/eks-auto-mode-sample

EKS は関連リソースが多くて定義が煩雑になりがちなので、下記公開モジュールを利用します。

https://registry.terraform.io/modules/terraform-aws-modules/eks/aws/latest

Terraform の EKS 構築部分は下記のようになります。

module "eks" {
  source  = "terraform-aws-modules/eks/aws"
  version = "~> 20.31.6"

  cluster_name                   = "test-cluster"
  cluster_version                = "1.31"
  cluster_endpoint_public_access = true

  vpc_id     = module.vpc.vpc_id
  subnet_ids = module.vpc.private_subnets

  enable_cluster_creator_admin_permissions = true

  cluster_compute_config = {
    enabled    = true
    node_pools = ["general-purpose"]
  }
}

data "aws_iam_policy_document" "allow_pod_identity" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["pods.eks.amazonaws.com"]
    }

    actions = [
      "sts:AssumeRole",
      "sts:TagSession"
    ]
  }
}

resource "aws_iam_role" "read_dynamodb" {
  name               = "read-dynamodb-role"
  assume_role_policy = data.aws_iam_policy_document.allow_pod_identity.json
}

resource "aws_iam_role_policy_attachment" "read_dynamodb" {
  role       = aws_iam_role.read_dynamodb.name
  policy_arn = "arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess"
}

resource "aws_eks_pod_identity_association" "read_dynamodb" {
  cluster_name    = module.eks.cluster_name
  namespace       = "app"
  service_account = "app-sa"
  role_arn        = aws_iam_role.read_dynamodb.arn
}

cluster_compute_configenabled=true に設定することで Auto Mode を有効化できます。
module.eks が EKS クラスター自体の定義で、それ以降は Pod Identity の定義になります。
ここでは Service Account(app-sa) を指定した Pod に DynamoDB の読み取り権限を付与しています。
また、アドオンは一つも追加していません。
今回利用する AWS Load Balancer Controller と Pod Identity エージェントは最初からインストールされているので、特に設定不要で利用できます。
ノードの管理についても Auto Mode の裏で動作している Karpenter に任せるため、設定不要です。
IRSA は利用しないため、OIDC ID プロバイダー関連の設定も不要になります。

スクリーンショット 2024-12-29 19.21.47.png

アプリケーションとしては DynamoDB の項目を読み取って表示するだけの簡単な物を利用します。

from fastapi import FastAPI
import boto3

app = FastAPI()

@app.get("/")
def read_root():
    dynamodb = boto3.client("dynamodb", region_name="ap-northeast-1")
    response = dynamodb.scan(
        TableName="test-dynamodb",
    )
    return response["Items"]

Terraform で作成した EKS クラスターに対して、Kubernetes リソースを作成していきます。
Namespace を作成します。

apiVersion: v1
kind: Namespace
metadata:
  name: app

Service Account を作成します。

apiVersion: v1
kind: ServiceAccount
metadata:
  name: app-sa
  namespace: app

作成した Service Account を指定して、アプリケーションをデプロイします。
Pod Identity で app-sa に対して権限を付与しているので、これらの Pod から DynamoDB にアクセスできます。

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: app
  name: fastapi-app
spec:
  selector:
    matchLabels:
      app.kubernetes.io/name: fastapi-app
  replicas: 2
  template:
    metadata:
      labels:
        app.kubernetes.io/name: fastapi-app
    spec:
      serviceAccountName: app-sa
      containers:
        - image: <AccountID>.dkr.ecr.ap-northeast-1.amazonaws.com/fastapi-app:latest
          imagePullPolicy: Always
          name: fastapi-app
          ports:
            - containerPort: 8080
          resources:
            requests:
              cpu: "0.5"

Pod を作成したタイミングで、Karpenter が自動でノードを作成してくれました。
AWS に任せられる範囲が増えて良い感じです。

スクリーンショット 2024-12-29 19.15.51.png

インターネット経由でアプリケーションにアクセスしたいので、Ingress 関連のリソースをデプロイしていきます。
まず Service をデプロイします。

apiVersion: v1
kind: Service
metadata:
  namespace: app
  name: app-service
spec:
  ports:
    - port: 8080
      targetPort: 8080
      protocol: TCP
  type: NodePort
  selector:
    app.kubernetes.io/name: fastapi-app

IngressClass をデプロイします。

apiVersion: networking.k8s.io/v1
kind: IngressClass
metadata:
  namespace: app
  labels:
    app.kubernetes.io/name: LoadBalancerController
  name: alb
spec:
  controller: eks.amazonaws.com/alb

Ingress をデプロイします。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  namespace: app
  name: app-ingress
  annotations:
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ingressClassName: alb
  rules:
    - http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: app-service
                port:
                  number: 8080

DynamoDB にサンプルデータを格納します。

スクリーンショット 2024-12-29 18.55.33.png

ALB が作成されていることを確認します。

% kubectl get ingress -n app
NAME          CLASS   HOSTS   ADDRESS                                                                   PORTS   AGE
app-ingress   alb     *       k8s-app-appingre-87880d3dc3-2089073335.ap-northeast-1.elb.amazonaws.com   80      9s

ALB の DNS 名に対してリクエストを送ると DynamoDB のデータを取得できています。

% curl http://k8s-app-appingre-87880d3dc3-2089073335.ap-northeast-1.elb.amazonaws.com/
[{"UserId":{"S":"2"},"Point":{"N":"70"}},{"UserId":{"S":"1"},"Point":{"N":"80"}}]

Pod Identity エージェント、AWS Load Balancer Controller、Karpenter と全て設定不要で利用することができました!

まとめ

Auto Mode のクラスターを構築して、AWS 権限を必要とするアプリケーションの公開まで実施してみました。
Auto Mode では管理する対象が減るので Terraform の記載もシンプルになって良いですね。
直近 EKS をよりシンプルに使うためのアップデートが継続的に公開されており、1 年半前くらいと比べて設定に躓きそうな部分も格段に減った気がします。
皆さんも是非試してみて下さい!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.